#ifndef __M_THREAD_H__
#define __M_THREAD_H__

#include <unistd.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <time.h>
#include <errno.h>
#include <poll.h>
#include <setjmp.h>
#include <pthread.h>

#ifdef __cplusplus
extern "C" {
#endif
	
#define MT_BEGIN_MACRO  {
#define MT_END_MACRO    }	
	
#define VCPU_ERROR 0xffffffff	
	
#define _MT_MT_RUNNING      0 
#define _MT_MT_RUNNABLE     1
#define _MT_MT_IO_WAIT      2
#define _MT_MT_LOCK_WAIT    3
#define _MT_MT_COND_WAIT    4
#define _MT_MT_SLEEPING     5
#define _MT_MT_ZOMBIE       6
#define _MT_MT_NOTCOND_WAIT 7
	
	typedef struct _mt_clist {
		struct _mt_clist *next;
		struct _mt_clist *prev;
	} _mt_clist_t;
	
	typedef struct _mt_stack {
		_mt_clist_t links;
		char *vaddr;                /* Base of stack's allocated memory */
		uint32_t  vaddr_size;            /* Size of stack's allocated memory */
		uint32_t  stk_size;              /* Size of usable portion of the stack */
		char *stk_bottom;           /* Lowest address of stack's usable portion */
		char *stk_top;              /* Highest address of stack's usable portion */
		void *sp;                   /* Stack pointer from C's point of view */
	} _mt_stack_t;
	
	typedef struct _mt_cond {
		_mt_clist_t wait_q;	      /* Condition variable wait queue */
	} _mt_cond_t;
	
	typedef pthread_mutex_t mt_mutex_t;
	
	struct _mt_thread {
		int state;                  /* Thread's state */
		int flags;                  /* Thread's flags */
		int waitRound;
		int waitValue;
		int ID;
  		char vcpu;
				 
		union {
			int* data;
			int fd;
		} desc;
					 
		void (*start)(void *arg);  
		void *arg;          
		void *retval;               
					 
		_mt_stack_t *stack;	
		_mt_thread *prev, *next;
		void **private_data;     
		_mt_cond_t *term; 
		jmp_buf context;           
	};
	
	typedef struct _mt_thread * mt_thread_t;
	extern ssize_t mt_read(int fd, void *buf, size_t nbytes, int spins = -1);
	extern ssize_t mt_write(int fd, void *buf, size_t nbytes, int spins = -1);
	
	//extern void _mt_delete_stacks();
	extern void vp_destroy();
	extern uint32_t mt_get_vcpu();
	extern void _mt_vp_schedule();
	extern uint32_t vp_init(uint32_t);
	extern void mt_join_all();
	
	extern int mt_mutex_lock(mt_mutex_t *mtx);
	extern int mt_mutex_unlock(mt_mutex_t *mt );
	extern int mt_mutex_init(mt_mutex_t *mtx);
	extern void mt_noop();
	extern mt_thread_t mt_thread_self();
	extern void mt_thread_exit();
	extern mt_thread_t mt_thread_create(void (*start)(void *arg), void *arg);
#ifdef __cplusplus
}
#endif

#define _MT_SWITCH_CONTEXT(_thread, vp)       								\
				MT_BEGIN_MACRO	                        					\
					if (!_setjmp((_thread)->context))  		\
				 		_mt_vp_schedule();       	           				\
					else 													\
   						mt_noop();	            							\
				MT_END_MACRO 


#endif

